﻿namespace ClassyBlog.DataAccess.Specs.Unit
{
    using System;

    using Machine.Specifications;
    using NSubstitute;

    using Infrastructure;

    public class ArticleFactoryTestDouble : ArticleFactory<Article>
    {
        public ArticleFactoryTestDouble(IFileSystem fileSystem) :
            base(fileSystem)
        {
        }

        protected override Article CreateLazy(string dataPath, string filePath)
        {
            return new Article();
        }
    }

    public abstract class ArticleFactorySpec
    {
        protected const string DataPath =
            @"c:\inetpub\wwwroot\classyblog\app_data\articles";

        protected const string FileName = "2010-04-02-17-30-00_hello-world.md";

        protected static IFileSystem fileSystem;
        protected static ArticleFactory<Article> factory;

        protected static Article article;

        Establish context = () =>
        {
            fileSystem = Substitute.For<IFileSystem>();
            factory = new ArticleFactoryTestDouble(fileSystem);
        };
    }

    [Subject(typeof(ArticleFactory<Article>))]
    public class when_article_is_created : ArticleFactorySpec
    {
        Establish context = () =>
            fileSystem.FileExists(Arg.Any<string>()).Returns(true);

        Because of = () =>
            article = factory.Create(DataPath, DataPath + "/" + FileName);

        It should_read_published_at_from_file_name = () =>
            article.PublishedAt.ShouldEqual(
            new DateTime(2010, 4, 2, 17, 30, 00));

        It should_read_slug_from_file_name = () =>
            article.Slug.ShouldEqual("hello-world");

        It should_read_type_from_file_extension = () =>
            article.Type.ShouldEqual("md");
    }

    [Subject(typeof(ArticleFactory<Article>))]
    public class when_article_factory_is_created_with_null_file_system
    {
        static Exception exception;

        Because of = () => exception =
            Catch.Exception(() => new ArticleFactoryTestDouble(null));

        It should_throw_exception = () =>
            exception.ShouldBeOfType<ArgumentNullException>();
    }

    [Behaviors]
    public class NullArticle
    {
        protected static Article article;

        It should_return_null = () => article.ShouldBeNull();
    }

    [Subject(typeof(ArticleFactory<Article>))]
    public class when_creating_article_with_blank_data_path :
        ArticleFactorySpec
    {
        static Exception exception;

        Because of = () => exception =
            Catch.Exception(() =>
                factory.Create(string.Empty, DataPath + "/" + FileName));

        It should_throw_exception = () =>
            exception.ShouldBeOfType<ArgumentException>();
    }

    [Subject(typeof(ArticleFactory<Article>))]
    public class when_creating_article_with_blank_file_path :
        ArticleFactorySpec
    {
        static Exception exception;

        Because of = () => exception =
            Catch.Exception(() => factory.Create(DataPath, string.Empty));

        It should_throw_exception = () =>
            exception.ShouldBeOfType<ArgumentException>();
    }

    [Subject(typeof(ArticleFactory<Article>))]
    public class when_creating_article_for_non_existent_file :
        ArticleFactorySpec
    {
        Establish context = () =>
            fileSystem.FileExists(Arg.Any<string>()).Returns(false);

        Because of = () =>
            article = factory.Create(DataPath, DataPath + "/" + FileName);

        Behaves_like<NullArticle> null_article;
    }

    [Subject(typeof(ArticleFactory<Article>))]
    public class when_creating_article_for_unnamed_file :
        ArticleFactorySpec
    {
        Establish context = () =>
            fileSystem.FileExists(Arg.Any<string>()).Returns(true);

        Because of = () =>
            article = factory.Create(DataPath, DataPath + "/" + ".md");

        Behaves_like<NullArticle> null_article;
    }

    [Subject(typeof(ArticleFactory<Article>))]
    public class when_creating_article_for_extension_less_file :
        ArticleFactorySpec
    {
        Establish context = () =>
            fileSystem.FileExists(Arg.Any<string>()).Returns(true);

        Because of = () =>
            article = factory.Create(DataPath, DataPath + "/" + "hello-world");

        Behaves_like<NullArticle> null_article;
    }

    [Subject(typeof(ArticleFactory<Article>))]
    public class when_creating_article_with_no_separator :
        ArticleFactorySpec
    {
        Establish context = () =>
            fileSystem.FileExists(Arg.Any<string>()).Returns(true);

        Because of = () =>
            article = factory.Create(
            DataPath, DataPath + "/" + "0000-00-00-00-00-00-hello-world.md");

        Behaves_like<NullArticle> null_article;
    }

    [Subject(typeof(ArticleFactory<Article>))]
    public class when_creating_article_which_with_no_publish_date :
        ArticleFactorySpec
    {
        Establish context = () =>
            fileSystem.FileExists(Arg.Any<string>()).Returns(true);

        Because of = () =>
            article = factory.Create(
            DataPath, DataPath + "/" + "0000-00-00-00-00-00_hello-world.md");

        Behaves_like<NullArticle> null_article;
    }
}